package com.lyandwc.lw_bbs.security.utils;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.lyandwc.lw_bbs.security.config.JWTConfig;
import com.lyandwc.lw_bbs.security.entity.UserAuthDetails;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import java.util.*;

public class JWTUtils {
    public static String createToken(UserAuthDetails userAuthDetails) {
        String token = Jwts.builder()
                .setId(
                        String.valueOf(userAuthDetails.getId())
                ).setSubject(
                        userAuthDetails.getUsername()
                ).setIssuedAt(
                        new Date()
                ).setIssuer(
                        "LWBBS"
                ).setExpiration(
                        new Date(System.currentTimeMillis() + JWTConfig.expiration)
                ).signWith(
                        SignatureAlgorithm.HS256, JWTConfig.secret
                ).claim(
                        "authorities", JSON.toJSONString(userAuthDetails.getAuthorities())
                ).compact();

        return JWTConfig.tokenPrefix + token;
    }

    public static UserAuthDetails parseToken(String token) {
        UserAuthDetails userAuthDetails = null;
        if (!StringUtils.isEmpty(token)) {
            try {
                token = token.substring(JWTConfig.tokenPrefix.length());

                Claims claims = Jwts.parser()
                        .setSigningKey(JWTConfig.secret)
                        .parseClaimsJws(token)
                        .getBody();

                Set<GrantedAuthority> authorities = new HashSet<>();
                String authorityStr = claims.get("authorities").toString();
                if (!StringUtils.isEmpty(authorityStr)) {
                    List<Map<String, String>> authorityList = JSON.parseObject(
                            authorityStr,
                            new TypeReference<List<Map<String, String>>>() {
                            }
                    );
                    for (Map<String, String> role : authorityList) {
                        if (!role.isEmpty()) {
                            authorities.add(new SimpleGrantedAuthority(role.get("authority")));
                        }
                    }
                }

                userAuthDetails = new UserAuthDetails();
                userAuthDetails.setId(Integer.parseInt(claims.getId()));
                userAuthDetails.setUsername(claims.getSubject());
                userAuthDetails.setAuthorities(authorities);
            } catch (Exception e) {

            }
        }
        return userAuthDetails;
    }

    public static String refreshToken(String token) {
        String refreshToken = null;
        if (!StringUtils.isEmpty(token)) {
            token = token.substring(JWTConfig.tokenPrefix.length());

            Claims claims = Jwts.parser()
                    .setSigningKey(JWTConfig.secret)
                    .parseClaimsJws(token)
                    .getBody();

            if (claims.getExpiration().before(new Date(System.currentTimeMillis() + 30000))) {
                refreshToken = Jwts.builder()
                        .setId(
                                claims.getId()
                        ).setSubject(
                                claims.getSubject()
                        ).setIssuedAt(
                                new Date()
                        ).setIssuer(
                                claims.getIssuer()
                        ).setExpiration(
                                new Date(System.currentTimeMillis() + JWTConfig.expiration)
                        ).signWith(
                                SignatureAlgorithm.HS256, JWTConfig.secret
                        ).claim(
                                "authorities", claims.get("authorities")
                        ).compact();
            }
        }

        return (refreshToken != null) ? JWTConfig.tokenPrefix + refreshToken : null;
    }
}
